package com.blue.code.src.jdbc;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;

import com.blue.code.src.Parser;
import com.blue.code.src.Table;
import com.blue.code.src.TableColumn;
import com.blue.code.src.TableId;

/**
 * 从数据库链接解析
 * 
 * @author zhengj
 * @since 1.0 2017年1月19日
 */

public class JdbcTableParser implements Parser
{
	private static Logger logger = LoggerFactory.getLogger(JdbcTableParser.class);
	
	@Value("${jdbc.url}")
	private String url;
	@Value("${jdbc.username}")
	private String username;
	@Value("${jdbc.password}")
	private String password;
	@Value("${table.names}")
	private String tables;
	@Value("${table.prefix.trim}")
	private boolean prefix;
	
	public JdbcTableParser()
	{
	}
	
	public List<Table> parse()
	{
		try (Connection conn = DriverManager.getConnection(url, username, password);)
		{
			DatabaseMetaData meta = conn.getMetaData();
			Set<String> nameSet = this.parseTable(meta);
			nameSet = this.checkTable(tables, nameSet);
			
			List<Table> tableList = new ArrayList<>();
			for (String table : nameSet)
			{
				tableList.add(this.parseColumn(meta, table));
			}
			return tableList;
		}
		catch (SQLException e)
		{
			logger.error("有错误：", e);
			throw new JdbcException("连接数据库异常");
		}
	}
	
	private Table parseColumn(DatabaseMetaData meta, String table) throws SQLException
	{
		Table jdbcTable = new Table();
		jdbcTable.setPrefix(prefix);
		jdbcTable.setTable(table);
		Map<String, TableId> idMap = new HashMap<>();
		try (ResultSet rs = meta.getPrimaryKeys(null, null, table))
		{
			List<TableId> idList = new ArrayList<>();
			jdbcTable.setIdList(idList);
			while (rs.next())
			{
				String name = rs.getString("COLUMN_NAME");
				
				TableId id = new TableId();
				id.setColumn(name);
				idList.add(id);
				idMap.put(name, id);
			}
		}
		try (ResultSet rs = meta.getColumns(null, null, table, null))
		{
			List<TableColumn> columnList = new ArrayList<>();
			jdbcTable.setColumnList(columnList);
			while (rs.next())
			{
				String name = rs.getString("COLUMN_NAME");
				int type = rs.getInt("DATA_TYPE");
				String typeName = rs.getString("TYPE_NAME");
				int size = rs.getInt("COLUMN_SIZE");
				String nullable = rs.getString("IS_NULLABLE");
				String inc = rs.getString("IS_AUTOINCREMENT");
				String def = rs.getString("COLUMN_DEF");
				String comment = rs.getString("REMARKS");
				
				TableId id = idMap.get(name);
				if (id != null)
				{
					id.setInc(!"NO".equals(inc));
				}
				TableColumn column = id;
				if (column == null)
				{
					column = new TableColumn();
					column.setColumn(name);
					columnList.add(column);
				}
				column.setType(type);
				column.setTypeName(typeName);
				column.setSize(size);
				column.setNullable(!"NO".equals(nullable));
				column.setDef("NULL".equals(def) ? null : def);
				column.setComment(comment);
			}

		}
		return jdbcTable;
	}
	
	private Set<String> checkTable(String tables, Set<String> nameSet)
	{
		if (tables == null || tables.isEmpty())
			return nameSet;
		
		Set<String> newSet = new HashSet<>();
		for (String table : tables.split(","))
		{
			table = table.trim();
			if (!nameSet.contains(table))
				throw new JdbcException("表不存在：" + table);
			
			newSet.add(table);
		}
		return newSet;
	}
	
	private Set<String> parseTable(DatabaseMetaData meta) throws SQLException
	{
		Set<String> nameSet = new HashSet<>();
		try (ResultSet rs = meta.getTables(null, null, null, new String[] {"TABLE"}))
		{
			while (rs.next())
			{
				String name = rs.getString("TABLE_NAME");
				nameSet.add(name);
			}
		}
		return nameSet;
	}
	
}
